package com.yangzc.lion.common.dao;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.transform.Transformers;

import com.yangzc.lion.common.model.IBaseModel;
import com.yangzc.lion.common.tag.Page;
import com.yangzc.lion.sys.util.StringUtil;

public abstract class BaseDaoImp<T extends IBaseModel> extends
		AbstractBaseDao<T, String> {

	private IHQLBuilder hqlBuilder;

	/**
	 * 设置HQL拼装器
	 * 
	 * @param hqlBuilder
	 */
	public void setHqlBuilder(IHQLBuilder hqlBuilder) {
		this.hqlBuilder = hqlBuilder;
	}

	public String add(T modelObj) throws RuntimeException {
		modelObj.recalculateFields();
		this.getHibernateSession().save(modelObj);
		return modelObj.getFdId();
	}

	public void delete(T modelObj) throws RuntimeException {
		this.getHibernateSession().delete(modelObj);
	}

	public void flushHibernateSession() {
		this.getHibernateSession().flush();
	}

	public void clearHibernateSession() {
		this.getHibernateSession().clear();
	}

	public T findByPrimaryKey(String id) throws RuntimeException {
		return findByPrimaryKey(getModelClass(), id, false);
	}

	public T findByPrimaryKey(String id, boolean noLazy)
			throws RuntimeException {
		return findByPrimaryKey(getModelClass(), id, noLazy);
	}

	public T findByPrimaryKey(Class<T> modelInfo, String id, boolean noLazy)
			throws RuntimeException {
		T rtnVal = null;
		if (id != null) {
			if (noLazy) {
				rtnVal = (T) this.getHibernateSession().get(modelInfo, id);
			} else {
				rtnVal = (T) this.getHibernateSession().load(modelInfo, id);
			}
		}
		return rtnVal;
	}

	public List<T> findByPrimaryKeys(String[] ids) throws RuntimeException {
		List<T> modelList = new ArrayList<T>();
		T model;
		for (int i = 0; i < ids.length; i++) {
			model = findByPrimaryKey(ids[i]);
			if (model != null)
				modelList.add(model);
		}
		return modelList;
	}

	public void update(T modelObj) throws RuntimeException {
		this.getHibernateSession().saveOrUpdate(modelObj);
	}

	public Session getHibernateSession() {
		return this.getSessionFactory().getCurrentSession();
	}

	public abstract Class<T> getModelClass();

	@SuppressWarnings("unchecked")
	public List<T> find(String hql, Map<String, Object> param,
			Integer firstResult, Integer rows) {
		Query q = this.getHibernateSession().createQuery(hql);
		if (param != null) {
			q.setProperties(param);
		}
		if (firstResult != null && firstResult > 0) {
			q.setFirstResult(firstResult);
		}
		if (rows != null && rows > 0) {
			q.setMaxResults(rows);
		}
		return q.list();
	}

	public List<T> find(String hql, Map<String, Object> param) {
		return find(hql, param, null, null);
	}

	public List<T> find(String hql) {
		return find(hql, null, null, null);
	}

	public Object findObject(String hql, Map<String, Object> param,
			Integer firstResult, Integer rows) {
		List<?> list = findObjects(hql, param, firstResult, rows);
		if (list != null && !list.isEmpty()) {
			return findObjects(hql, param, firstResult, rows).get(0);
		}
		return null;
	}

	public Object findObject(String hql, Map<String, Object> param) {
		return findObject(hql, param, null, null);
	}

	public Object findObject(String hql) {
		return findObject(hql, null, null, null);
	}

	public List<?> findObjects(String hql, Map<String, Object> param,
			Integer firstResult, Integer rows) {
		Query q = this.getHibernateSession().createQuery(hql);
		if (param != null) {
			q.setProperties(param);
		}
		if (firstResult != null && firstResult > 0) {
			q.setFirstResult(firstResult);
		}
		if (rows != null && rows > 0) {
			q.setMaxResults(rows);
		}
		return q.list();
	}

	public List<?> findObjects(String hql, Map<String, Object> param) {
		return findObjects(hql, param, null, null);
	}

	public List<?> findObjects(String hql) {
		return findObjects(hql, null, null, null);
	}

	public Integer executeHql(String hql, Map<String, Object> param) {
		Query q = this.getHibernateSession().createQuery(hql);
		if (param != null) {
			q.setProperties(param);
		}
		return q.executeUpdate();
	}

	public Integer executeHql(String hql) {
		return executeHql(hql, null);
	}

	@SuppressWarnings("unchecked")
	public Page<T> findPage(HQLInfo hqlInfo) {
		Page<T> page = null;
		int total = hqlInfo.getPageSize();
		if (hqlInfo.isGetCount()) {
			hqlInfo.setGettingCount(true);
			total = ((Long) createHbmQuery(hqlInfo).iterate().next())
					.intValue();
		}
		if (total > 0) {
			hqlInfo.setGettingCount(false);
			page = new Page<T>();
			page.setPageSize(hqlInfo.getPageSize());
			page.setPageNo(hqlInfo.getPageNo());
			page.setTotalSize(total);
			page.excecute();
			Query q = createHbmQuery(hqlInfo);
			q.setFirstResult(page.getOffset());
			q.setMaxResults(page.getPageSize());
			page.setRows(q.list());
		}
		if (page == null) {
			page = Page.getEmptyPage();
		}
		return page;
	}

	@SuppressWarnings("unchecked")
	public Page<Map<String, Object>> findObjectPage(HQLInfo hqlInfo) {
		Page<Map<String, Object>> page = null;
		int total = hqlInfo.getPageSize();
		if (hqlInfo.isGetCount()) {
			hqlInfo.setGettingCount(true);
			total = ((Long) createHbmQuery(hqlInfo).iterate().next())
					.intValue();
		}
		if (total > 0) {
			hqlInfo.setGettingCount(false);
			page = new Page<Map<String, Object>>();
			page.setPageSize(hqlInfo.getPageSize());
			page.setPageNo(hqlInfo.getPageNo());
			page.setTotalSize(total);
			page.excecute();
			Query q = createHbmQuery(hqlInfo);
			q.setFirstResult(page.getOffset());
			q.setMaxResults(page.getPageSize());
			q.setResultTransformer(Transformers.ALIAS_TO_ENTITY_MAP);
			page.setRows(q.list());
		}
		if (page == null) {
			page = Page.getEmptyPage();
		}
		return page;
	}

	protected Query createHbmQuery(HQLInfo hqlInfo) {
		if (StringUtil.isNull(hqlInfo.getModelName()))
			hqlInfo.setModelName(this.getModelClass().getName());
		HQLWrapper hqlWrapper = hqlBuilder.buildQueryHQL(hqlInfo);
		Query query = this.getHibernateSession().createQuery(
				hqlWrapper.getHql());
		query.setProperties(hqlWrapper.getParameterMap());
		return query;
	}
	
	public List findList(HQLInfo hqlInfo){
		hqlInfo.setFromBlock(null);
		List rtnList = createHbmQuery(hqlInfo).list();
		return rtnList;
	}
	
	public List findList(String whereBlock, String orderBy){
		HQLInfo hqlInfo = new HQLInfo();
		hqlInfo.setWhereBlock(whereBlock);
		hqlInfo.setOrderBy(orderBy);
		return findList(hqlInfo);
	}
}
